/**
 * @file PlayState.h
 *
 * Estado de juego.
 */

#ifndef __PlayState_h__
#define __PlayState_h__

#include <cstdlib>
#include <time.h>
#include <vector>
#include <list>
#include <iterator>
#include <Ogre.h>
#include <OIS/OIS.h>
#include <btBulletDynamicsCommon.h>
#include "ZombieManager.h"
#include "StageManager.h"
#include "HumanManager.h"
#include "Human.h"
#include "BtOgrePG.h"
#include "BtOgreGP.h"
#include "BtOgreExtras.h"
#include <TrackManager.h>
#include <SoundFXManager.h>
#include <GameManager.h>

#include <GameState.h>
// #include "RecordManager.h"

/// Estado de juego.
class PlayState: public Ogre::Singleton<PlayState>, public GameState
{
  public:
    /// Constructor.
    PlayState();

    /// Destructor.
    ~PlayState() throw();

    /// Se ejecuta al iniciar este estado.
    void enter();

    /// Se ejecuta al salir de este estado.
    void exit();

    /// Se ejecuta al pausar este estado.
    void pause();

    /// Se ejecuta al volver de una pausa desde otro estado.
    void resume();

    /**
     * Detecta cuando se ha pulsado una tecla.
     *
     * @param[in] e Tecla pulsada.
     */
    void keyPressed(const OIS::KeyEvent& e);

    /**
     * Detecta cuando se ha soltado una tecla.
     *
     * @param[in] e Tecla soltada.
     */
    void keyReleased(const OIS::KeyEvent& e);

    /**
     * Detecta cuando se ha movido el ratón.
     *
     * @param[in] e Evento del ratón.
     */
    void mouseMoved(const OIS::MouseEvent& e);

    /**
     * Detecta cuando se ha pulsado un botón del ratón.
     *
     * @param[in] e  Evento del ratón.
     * @param[in] id Botón pulsado.
     */
    void mousePressed(const OIS::MouseEvent& e, OIS::MouseButtonID id);

    /**
     * Detecta cuando se ha soltado un botón del ratón.
     *
     * @param[in] e  Evento del ratón.
     * @param[in] id Botón soltado.
     */
    void mouseReleased(const OIS::MouseEvent& e, OIS::MouseButtonID id);

    /**
     * Se ejecuta cuando se va a renderizar un frame.
     *
     * @param[in] evt Estructura con información acerca del frame.
     */
    virtual bool frameStarted(const Ogre::FrameEvent& evt);

    /**
     * Se ejecuta cuando se ha terminado de renderizar un frame.
     *
     * @param[in] evt Estructura con información acerca del frame.
     */
    virtual bool frameEnded(const Ogre::FrameEvent& evt);

    // Heredados de Ogre::Singleton.

    /// Devuelve una referencia a este singleton.
    static PlayState& getSingleton();

    /// Devuelve un puntero a este singleton.
    static PlayState* getSingletonPtr();

  private:
    Ogre::Root* _root;                     ///< Nodo root.
    Ogre::SceneManager* _sceneManager;     ///< SceneManager.
    Ogre::Viewport* _viewport;             ///< Viewport.
    Ogre::Camera* _camera;                 ///< Cámara.
    Ogre::RenderWindow* _window;           ///< Ventana.
    Ogre::OverlayManager* _overlayManager; ///< OverlayManager.
    Ogre::RaySceneQuery* _raySceneQuery;   ///< RaySceneQuery.

    int _score;     ///< Puntuación
    bool _exitGame; ///< True cuando ha terminado este estado.

    TrackManager* _pTrackManager;     ///< TrackManager de SDL.
    SoundFXManager* _pSoundFXManager; ///< SoundFXManager de SDL.

    TrackPtr _ost;   ///< Banda sonora de fondo.
    SoundFXPtr _shoot; ///< Sonido disparo.
    SoundFXPtr _bite; ///< Sonido mordisco de zombi.
    SoundFXPtr _zombiKill; ///< Sonido zombi destruido.

    // Mundo bullet

    btBroadphaseInterface* _broadphase;
    btDefaultCollisionConfiguration* _collisionConf;
    btCollisionDispatcher* _dispatcher;
    btSequentialImpulseConstraintSolver* _solver;
    btDiscreteDynamicsWorld* _world;

    // btOgre
    BtOgre::DebugDrawer* _pDebugDrawer;

    // Gestores del juego
    HumanManager* _pHumanManager;
    ZombieManager* _pZombieManager;
    StageManager* _pStageManager;

    // Puntero al jefe
    Zombie* _pZombieBoss;

    // Overlay del ratón
    Ogre::OverlayElement* _mouseOverlay;
    int _posx, _posy;

    // Contador auxiliar
    float _counter;

    // Overlay de la vida del humano y del jefe
    Ogre::OverlayElement* _lifeOverlay;
    Ogre::OverlayElement* _zlifeOverlay;

    // Vectores de movimiento del personaje
    btVector3 _impulse;
    btVector3 _impulseWithoutRotation;

    // Rotación del personaje
    btScalar _rotation;

    // Último punto mirado.
    Ogre::Vector3 _lastPointLooked;

    // Cuenta de enemigos destruidos.
    int _killedCount;

    // Crea el mundo inicial
    void CreateInitialWorld();

    // Carga el nivel
    void LoadLevel();

    // Actualizar HUD
    void updateHUD();
};

#endif
